package com.fcat.springboot.redis.service.impl;


import com.fcat.springboot.redis.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class RedisServiceImpl implements RedisService {
    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public String getStringValue(String key) {
        return (String) redisTemplate.opsForValue().get(key);
    }

    @Override
    public void setStringValue(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }

    public void leftPushForList(String key, Object value) {
        redisTemplate.opsForList().leftPush(key, value);
    }

    public void rightPushForList(String key, Object value) {
        redisTemplate.opsForList().rightPush(key, value);
    }

    /**
     * 获取指定索引位置的值, index为-1时，表示返回的是最后一个；当index大于实际的列表长度时，返回null
     *
     * @param key
     * @param index
     * @return
     */
    public Object indexForList(String key, int index) {
        return redisTemplate.opsForList().index(key, index);
    }

    /**
     * * 获取范围值，闭区间，start和end这两个下标的值都会返回; end为-1时，表示获取的是最后一个；
     * *
     * * 如果希望返回最后两个元素，可以传入  -2, -1
     *
     * @param key
     * @param start
     * @param end
     * @return
     */
    public List<Object> rangeForList(String key, int start, int end) {
        return redisTemplate.opsForList().range(key, start, end);
    }

    public Long sizeForList(String key) {
        return redisTemplate.opsForList().size(key);
    }

    /**
     * 设置list中指定下标的值，采用干的是替换规则, 最左边的下标为0；-1表示最右边的一个
     *
     * @param key
     * @param index
     * @param value
     */
    public void setForList(String key, Integer index, Object value) {
        redisTemplate.opsForList().set(key, index, value);
    }

    /**
     * * 删除列表中值为value的元素，总共删除count次；
     * *
     * * 如原来列表为 【1， 2， 3， 4， 5， 2， 1， 2， 5】
     * * 传入参数 value=2, count=1 表示删除一个列表中value为2的元素
     * * 则执行后，列表为 【1， 3， 4， 5， 2， 1， 2， 5】
     * *
     *
     * @param key
     * @param value
     * @param count
     */
    public void removeForList(String key, Object value, int count) {
        redisTemplate.opsForList().remove(key, count, value);
    }

    /**
     * 删除list首尾，只保留 [start, end] 之间的值
     *
     * @param key
     * @param start
     * @param end
     */
    public void trimForList(String key, Integer start, Integer end) {
        redisTemplate.opsForList().trim(key, start, end);
    }

    public Object leftPopForList(String key) {
        return redisTemplate.opsForList().leftPop(key);
    }

    public Object rightPopForList(String key) {
        return redisTemplate.opsForList().rightPop(key);
    }

    @Override
    public boolean setValue(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Override
    public boolean setValue(String key, Object value, Long time, TimeUnit util) {
        try {
            redisTemplate.opsForValue().set(key, value, time, util);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Override
    public boolean setValue(String key, Object value, Long time) {
        try {
            redisTemplate.opsForValue().set(key, value, time);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Override
    public Object getValue(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    @Override
    public void deleteKey(String key) {
        redisTemplate.delete(key);
    }

    @Override
    public Set getKeys(String s) {
        return redisTemplate.keys(s);
    }

    @Override
    public List getValuesByKeys(Set<String> keys) {
        return redisTemplate.opsForValue().multiGet(keys);
    }

    @Override
    public void mapPutAll(String hashName, Map<String, Object> map) {
        redisTemplate.opsForHash().putAll(hashName, map);
    }


    @Override
    public void mapPut(String hashName, String hashKey, Object hashValue) {
        redisTemplate.opsForHash().put(hashName, hashKey, hashValue);
    }

    @Override
    public <V> void mapPutList(Class<V> v, String hashName, Map<String, List<V>> map) {
        redisTemplate.opsForHash().putAll(hashName, map);
    }

    @Override
    public <V> void mapPutMap(Class<V> v, String hashName, Map<String, V> map) {
        redisTemplate.opsForHash().putAll(hashName, map);
    }

    @Override
    public <K, V> void mapPutMap(Class<K> k, Class<V> v, String hashName, Map<String, Map<K, V>> map) {
        redisTemplate.opsForHash().putAll(hashName, map);
    }

    @Override
    public Object mapGet(String hashName, String hashKey) {
        Object object = redisTemplate.opsForHash().get(hashName, hashKey);
        return object;
    }

    @Override
    public void mapDelete(String hashName, String... hashKey) {
        redisTemplate.opsForHash().delete(hashName, hashKey);
    }

    @Override
    public List<Object> mapGetAllValue(String hashName) {
        List<Object> objectList = redisTemplate.opsForHash().values(hashName);
        return objectList;
    }

    @Override
    public List<Object> mapGetAllKey(String hashName) {
        Set<Object> objectList = redisTemplate.opsForHash().keys(hashName);
        List<Object> tmpList = new ArrayList<Object>(objectList);
        return tmpList;
    }

    @Override
    public Long mapSize(String hashName) {
        return redisTemplate.opsForHash().size(hashName);
    }

    @Override
    public void mapClear(String hashName) {
        redisTemplate.delete(hashName);
    }

    @Override
    public Map<String, Object> mapGetAll(String hashName) {
        return redisTemplate.opsForHash().entries(hashName);
    }

    @Override
    public boolean setIsMember(String setName, String value) {
        return redisTemplate.opsForSet().isMember(setName, value);
    }

    @Override
    public Long setAdd(String setName, String value) {
        return redisTemplate.opsForSet().add(setName, value);
    }

    @Override
    public void setAdd(String setName, Object... value) {
        redisTemplate.opsForSet().add(setName, value);
    }

    @Override
    public void setAdd(String setName, String... value) {
        redisTemplate.opsForSet().add(setName, value);
    }
    @Override
    public Long setRemove(String setName, String value) {
        return redisTemplate.opsForSet().remove(setName, value);
    }
    @Override
    public <T> Set<T> setGetAll(Class<T> t, String setName) {
        return redisTemplate.opsForSet().members(setName);
    }

    @Override
    public Map<String, Object> batchQueryByKeys(List<String> keys) {
        RedisCallback redisCallback = new RedisCallback() {
            @Override
            public String doInRedis(RedisConnection connection) throws DataAccessException {
//                StringRedisConnection stringRedisConnection = (StringRedisConnection) connection;
                for (String key : keys) {
                    connection.get(key.getBytes());
                }
                return null;
            }
        };
        List list = redisTemplate.executePipelined(redisCallback);
        Map<String, Object> map = new HashMap<>();
        keys.parallelStream().forEach(s -> {
            map.put(s, list.get(keys.indexOf(s)));
        });
        return map;
    }

    public <T> Map<String, T> batchQueryMapByKeys(Class<T> clazz, String mapName, List<String> keys) {
        RedisCallback<T> redisCallback = (connect -> {
            keys.forEach(item -> connect.hGet(mapName.getBytes(), item.getBytes()));
            return null;
        });
        List<T> list = redisTemplate.executePipelined(redisCallback);
        LinkedHashMap<String, T> map = new LinkedHashMap<>();
        keys.stream().forEachOrdered(s -> map.put(s, list.get(keys.indexOf(s))));
        return map;
    }

    @Override
    public Set<String> getLeftLikeKeys(String key) {
        return redisTemplate.keys(key + "*");
    }

    public <T> Map<String, T> mapGetAll(Class<T> t, String hashName) {
        Map<String, T> result = redisTemplate.opsForHash().entries(hashName);
        return result;
    }


    public <K, V> Map<String, Map<K, V>> mapGetAll(Class<K> k, Class<V> v, String hashName) {
        Map<String, Map<K, V>> result = redisTemplate.opsForHash().entries(hashName);
        return result;
    }

    public <HK, HV> Map<HK, HV> mapGetAll2(Class<HK> hk, Class<HV> hv, String hashName) {
        Map<HK, HV> result = redisTemplate.opsForHash().entries(hashName);
        return result;
    }

    @Override
    public <T> Map<String, List<T>> mapGetList(Class<T> t, String hashName) {
        Map<String, List<T>> result = redisTemplate.opsForHash().entries(hashName);
        return result;
    }

}
